﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Data.Entity;
using System.Web.Security;


namespace BskLeague.Models
{
    public class AnnounceCommunicate : IValidatableObject
    {
        public int AnnounceCommunicateId { get; set; }
        public IList<AnnouncedPlayer> Players { get; set; }
        [Required]
        public String TeamName { get; set; }
        public DateTime AnnounceDate { get; set; }
        public int StatusId {get; set;}
        public virtual AnnounceCommunicateStatus Status {get; set;}
        public int ChefPlayerIndex { get; set; }
        public string PaymentFileName { get; set; }

        /**
         * Method saves the uploaded file in App_data folder.
         * Checks whether file is not null and content size bigger than 0
         * */
        internal void SavePaymentFile(HttpServerUtilityBase Server, HttpPostedFileBase PaymentFile)
        {
            if (PaymentFile != null && PaymentFile.ContentLength > 0)
            {
                // generate file name
                PaymentFileName = TeamName + "PaymentFile" + PaymentFile.FileName.Substring(PaymentFile.FileName.IndexOf('.'));

                // store the file inside ~/App_Data/uploads folder
                var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), PaymentFileName);
                PaymentFile.SaveAs(path);
            }
        }

        /**
         * Method confirms the announcement.
         * Pushes players from AnnouncedPlayers to Players (if necessary).
         * Creates user accounts (if necessary).
         * Creates new team (if necessary). 
         */
        internal void ConfirmAnnouncement(BskLeagueDB _db)
        {
            
            Season season = _db.Seasons.SingleOrDefault(s => "Recrutation" == s.Status.Status);
            if (season != null)
            {
                //pushing Team
                Team team = _db.Teams.SingleOrDefault(t => t.TeamName == TeamName);
                //there's no such team
                if (null == team)
                {
                    team = new Team { TeamName = TeamName };
                    _db.Teams.Add(team);
                }
                //team exists, so we need to get the chef out of Chef role
                else
                {
                    Roles.RemoveUserFromRole(team.ChefPlayer.UserName, "Chef");
                }

                //player to be set as chef
                Player chefPlayer = null;

                //Pushing AnnouncedPlayers
                for (int i = 0; i < Players.Count; i++)
                {
                    var p = Players[i];
                    Player player = _db.Players.SingleOrDefault(pl => pl.PlayerName == p.Name && pl.PlayerSurname == p.Surname && pl.Email == p.Email);
                    if (player != null)
                    {
                        SeasonTeamPlayer stp = new SeasonTeamPlayer { Season = season, Team = team, Player = player };
                        _db.SeasonTeamPlayers.Add(stp);

                        if (i == ChefPlayerIndex)
                        {
                            chefPlayer = player;
                            if (!Roles.IsUserInRole(player.UserName, "Chef"))
                            {
                                Roles.AddUserToRole(player.UserName, "Chef");
                            }
                        }
                    }
                }

            Status = _db.AnnounceCommunicateStatuses.SingleOrDefault(s => s.Status == "Confirmed");

            _db.Entry(team).Entity.ChefPlayer = chefPlayer;

            _db.SaveChanges();
            }
        }


        public IEnumerable<ValidationResult> 
            Validate(ValidationContext validationContext)
        {

            var _db = new BskLeagueDB();

            //check if team has been already announced
            var seasons = _db.Seasons.ToList();
            Season actualSeason = seasons.Find(s => s.Status.Status == "Recrutation");
            var stps = _db.SeasonTeamPlayers.ToList();


            if (stps.Any(s => s.Team.TeamName == TeamName && s.Season == actualSeason))
                yield return new ValidationResult("Team o tej nazwie został już zgłoszony do rozgrywek!");

            
            foreach (var p in Players)
            {
                //check if data is null
                if (p.Name == null)
                    yield return new ValidationResult("Imię zawodnika nie może być puste!");
                if (p.Surname == null)
                    yield return new ValidationResult("Nazwisko nie może być puste!");
                if (p.Email == null)
                    yield return new ValidationResult("Email zawodnika nie może być pusty!");

                //check if announced players personal data fits emails. Say - licence!
                if (p.LicenceId != null)
                {
                    var existingPlayer = _db.Players.Include("Licence").SingleOrDefault(pl => pl.LicenceId == p.LicenceId);
                    if (existingPlayer != null)
                    {

                        if (existingPlayer.PlayerName != p.Name || existingPlayer.PlayerSurname != p.Surname
                            || existingPlayer.Email != p.Email)
                            yield return new ValidationResult("Niezgodność adresu email i danych personalnych zawodnika: "
                                + p.Email + " " + p.Name + " " + p.Surname + p.LicenceId);
                        else
                        {
                            var season = _db.Seasons.SingleOrDefault(s => s.StatusId < 3);
                            if (season == null)
                            {
                                season = _db.Seasons.SingleOrDefault(s => s.SeasonId == _db.Seasons.Max(se => se.SeasonId));
                            }
                            if (stps.Any(stp => stp.PlayerId == existingPlayer.PlayerId && stp.SeasonId == season.SeasonId))
                            {
                                yield return new ValidationResult("Zawodnik o licencji: " + p.LicenceId.ToString() + " został już wpisany do innej drużyny na ten sezon");
                            }
                            p.InDatabase = true;
                        }
                    }
                }

            }


        }
    }
}